<?php
/**
 * @link https://ym2.cleverstone.top
 * @copyright Copyright (c) 2020 Yii Manager Software LLC
 */

namespace builder\uploads;

use Yii;
use yii\base\Component;
use yii\helpers\FileHelper;
use yii\validators\FileValidator;
use yii\web\UploadedFile;

/**
 * 驱动基座
 * @property-read string $error 错误信息
 * @property-read array $result 输出数据
 * @author cleverstone
 * @since ym2.0
 */
abstract class BaseProvider extends Component
{
    /**
     * @var string 文件字段
     */
    public $fileParam = 'file';
    /**
     * @var array|string 可使用的场景
     */
    public $allowScenarios = ['IMAGE', 'VIDEO', 'AUDIO', 'OTHER'];
    /**
     * @var array 支持的文件扩展名
     */
    public $extOptions = [
        'IMAGE' => ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg'],
        'VIDEO' => ['avi', 'mov', 'rmvb', 'rm', 'flv', 'mp4', '3gp'],
        'AUDIO' => ['cda', 'wav', 'mp3', 'aiff', 'aif', 'mid', 'wma', 'ra', 'vqf', 'ape', 'm4a'],
        'OTHER' => ['htm', 'html', 'zip', 'rar', 'txt', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf', 'log', 'woff', 'woff2', 'csv'],
    ];
    /**
     * @var int 支持的文件大小
     */
    public $maxSizeOptions = [
        'IMAGE' => 3145728,/* 3*1024*1024 */
        'VIDEO' => 209715200,/* 200*1024*1024 */
        'AUDIO' => 52428800,/* 50*1024*1024 */
        'OTHER' => 52428800,/* 50*1024*1024 */
    ];

    /**
     * @var string 当前场景
     */
    protected $scenario;

    /**
     * @var UploadedFile
     */
    protected $uploadFile;
    /**
     * @var string 上传错误
     */
    protected $error;

    /**
     * @var string 文件原名
     */
    protected $name;
    /**
     * @var string 文件链接
     */
    protected $link;
    /**
     * @var int 文件大小(字节)
     */
    protected $size;
    /**
     * @var string 文件扩展名
     */
    protected $ext;
    /**
     * @var string 文件类型扩展
     */
    protected $mime;
    /**
     * @var string 文件hash
     */
    protected $hash;
    /**
     * @var string 文件类型: 'IMAGE', 'VIDEO', 'AUDIO', 'OTHER'
     *
     */
    protected $type;

    /**
     * 初始化驱动
     * @throws \yii\base\InvalidConfigException
     */
    protected function initOptions()
    {
        $this->uploadFile = UploadedFile::getInstanceByName($this->fileParam);

        $this->name = $this->uploadFile->name;
        $this->size = $this->uploadFile->size;
        $this->ext = $this->uploadFile->extension;
        $this->mime = FileHelper::getMimeType($this->uploadFile->tempName);
        $this->hash = hash_file('md5', $this->uploadFile->tempName);

        foreach ($this->extOptions as $scenario => $exts) {
            if (in_array(strtolower($this->ext), array_map('strtolower', $exts))) {
                $this->scenario = $scenario;

                $this->type = $scenario;
                break;
            }
        }
    }

    /**
     * 文件校验
     * @return bool
     */
    protected function validate()
    {
        if (empty($this->scenario)) {
            $this->error = '不支持上传的文件类型!';
            return false;
        }

        $exts = [];
        foreach ((array)$this->allowScenarios as $sce) {
            $exts = array_merge($exts, $this->extOptions[$sce]);
        }

        $filename = $this->uploadFile->name;
        $maxSize = $this->maxSizeOptions[$this->scenario];
        $shortSize = Yii::$app->formatter->asShortSize($maxSize);

        if ($this->uploadFile->size > $maxSize) {
            $this->error = "文件\"{$filename}\"太大了。它的大小不能超过{$shortSize}。";
            return false;
        }

        $fileValidator = new FileValidator([
            'checkExtensionByMimeType' => false,//不通过mime校验扩展名
            'extensions' => $exts,
        ]);

        return $fileValidator->validate($this->uploadFile, $this->error);
    }

    /**
     * 移动文件
     * @param bool $deleteTempFile
     * @return bool
     * @throws \yii\base\InvalidConfigException
     */
    public function move($deleteTempFile = true)
    {
        $this->initOptions();

        if (!$this->validate()) {
            return false;
        }

        return $this->run($deleteTempFile);
    }

    /**
     * @return array
     */
    public function getResult()
    {
        $result = [
            'name' => $this->name,
            'link' => $this->link,
            'size' => $this->size,
            'ext' => $this->ext,
            'mime' => $this->mime,
            'hash' => $this->hash,
            'type' => $this->type,
        ];

        return $result;
    }

    /**
     * @return string
     */
    public function getError()
    {
        return $this->error;
    }

    /**
     * 移动文件
     * @param boolean $deleteTempFile 是否删除临时文件
     * @return boolean
     */
    abstract protected function run($deleteTempFile = true);
}